Skip to content

[script] Resolve names in the type pass from the entity scope chain, like evaluation - #2

Closed
Andrew Gazelka (andrewgazelka) wants to merge 1 commit into
masterfrom
script-type-scope-lookup
Closed

Andrew Gazelka (andrewgazelka) wants to merge 1 commit into
masterfrom
script-type-scope-lookup

Conversation

@andrewgazelka

Copy link
Copy Markdown
Member

Bug

A game runs several scripts in sequence with ecs_script_run:

// pieces.flecs
structure { prefabs { Prefab steel { ... } } }

// kinds.flecs
structure { prefabs { Prefab steel_a992 : steel { ... } } }

The second script fails with unresolved reference 'steel'. The error comes from the type-check visitor: flecs_script_type_report_unresolved ← flecs_script_type_lookup ← flecs_script_id_elem_lookup.

Root cause

flecs_script_symbol_lookup first tries the type pass's symbol table, which only holds names declared by this script. It then falls back to the world: FlecsMeta, then a recursive lookup from v->parent, then using paths, then the lookup action. Evaluation sets v->parent to each entity as it enters that entity's scope. The type pass did not: v->parent stayed at the outer parent of the script for the whole walk. As a result, names in an enclosing scope that exist only in the world were never found. Here that is structure.prefabs.steel, created by the previous script. Names declared in the same script did resolve, because they are script symbols.

Fix

flecs_script_type_entity now calls flecs_script_type_push_parent before typing an entity's scope and restores the previous parent afterwards:

  • If the entity already exists in the world, v->parent is set to it. The entity is found either from the node's symbol slot or with ecs_lookup_path_w_sep(world, v->parent, name), the same lookup evaluation uses to find or create it.
  • If it does not exist yet, v->parent is kept. Evaluation will create it with no children, so a recursive lookup from it gives the same result as a lookup from its parent.
  • Its descendants cannot exist either, so a parent_missing flag stops them from being looked up by name under the wrong parent.
  • Entities with a name expression and anonymous entities can't be looked up statically, so they also count as missing. Lookups inside them stay at the nearest scope that is known to exist.

With this, the type pass resolves names through the same chain as evaluation: this script's symbols, then FlecsMeta, the scope chain, using paths, and the lookup action.

The code that already set v->parent explicitly inside the type pass is unchanged, since it sets the parent from the owner itself before evaluating: export const, template, module, and type entities.

distr/flecs.c has the same change.

Tests (test/script, Eval)

New tests. Each runs two scripts in sequence and fails without the fix:

  • scoped_prefab_inherit_from_prev_script: structure { prefabs { Prefab steel { Foo } } }, then structure { prefabs { Prefab steel_a992 : steel {} } }. Checks the IsA relationship, the prefab, and the inherited Foo.
  • scoped_entity_ref_from_prev_script: (MadeOf, steel) resolving to structure.materials.steel, created by the earlier script.
  • scoped_component_from_prev_script: struct Profile(...) declared in structure.components by script 1 and set as Profile: {...} in the same scope by script 2. Checks the values.
  • nested_scope_component_from_prev_script: the component is declared in structure by script 1 and used one scope deeper, in structure.prefabs.mullion, by script 2.

Behaviour change, two existing tests updated. const_w_component_in_scope_expr_in_scope and const_w_component_and_entity_in_scope_expr_in_scope asserted that parent.Position (and parent.e), created from C, do not resolve inside parent { const pos = e[Position]; foo { Position: pos } } in a script. That assertion only held because of this bug. Evaluation looks up names recursively from parent.foo, which finds parent.Position, and the ..._in_module counterparts already passed. Both tests now assert that the script succeeds and that parent.foo gets Position {10, 20}.

Results

  • Script suite: 8812 passed, 0 failed (IR disabled and enabled).
  • Addons suite: 637 passed. Meta suite: 1492 passed.
  • distr/flecs.c compiles with -Wall -Wextra -Werror.

…ike evaluation

The type pass kept v->parent at the outer parent while typing entity scopes,
so names that only exist in the world (e.g. created by a previous script) in an
enclosing scope did not resolve, and were reported as unresolved references.
Set v->parent to the existing world entity of each entity scope before typing
it, as evaluation does.
@andrewgazelka

Copy link
Copy Markdown
Member Author

Superseded by the upstream PR SanderMertens#2380 (SanderMertens#2380).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant